import Singleton from './Singleton';
/** 敏感词节点 */
interface INode {
    c: string, // 字符
    flag: number, // 是否结束标志 0继续 1结尾
    nodes: INode[], // 保存子节点
}

/** 敏感词库转化关键词 dfa算法处理屏蔽词库 */
export default class SensitiveFilter extends Singleton {
	rootNode: INode;

	constructor() {
		super();
 
	}

	protected create(): void {
		// const words = ResMgr.loadConfigFile("shield_text"); // 从文件载入敏感词列表
		const words = ["敏感词", "dirty", "duck", "脏话", "脏了"]; // 测试用的词库

		this.createTree(words);
	}

	/** 树节点创建 */
	createNode(c: string, flag?: number, nodes?: INode[]): INode {
		const node:INode = {
			c: c||null, // 字符
			flag: flag||0, // 是否结束标志 0继续 1结尾
			nodes:nodes|| [], // 保存子节点
		};
		
		return node;
	}

	/** 初始化树结构 */
	createTree(words: string[]) {
		words = words || [];
		this.rootNode = this.createNode("R"); // 根节点（名字无所谓）
		this.addWords(words);
	}

	/** 添加敏感词 */
	addWords(words: string[]) {
		for (let i = 0, ln = words.length; i < ln; ++i) {
			const chars = this.getCharArray(words[i]);

			if (chars.length > 0) {
				this.insertNode(this.rootNode, chars, 0);
			}
		}
	}

	/** 插入节点 */
	insertNode(node: INode, cs: string[], index: number) {
		let n = this.findNode(node, cs[index]);

		if (n == null) {
			n = this.createNode(cs[index]);
			node.nodes.push(n);
		}

		if (index == cs.length - 1) {
			n.flag = 1;
		}

		index++;
		if (index <= cs.length - 1) {
			this.insertNode(n, cs, index);
		}
	}

	/** 节点中查找子节点 */
	findNode(node: INode, c: string): INode {
		const nodes = node.nodes;
		let rn: INode = null;

		for (let i = 0, ln = nodes.length; i < ln; ++i) {
			const v = nodes[i];

			if (v.c == c) {
				rn = v;
				break;
			}
		}

		return rn;
	}

	/** 字符串转换为字符数组 */
	getCharArray(str: string): string[] {
		str = str || "";
		// ts里用的都是utf8，汉字和英文一样，占一个字符
		const arr: string[] = [];

		for (let i = 0, ln = str.length; i < ln; ++i) {
			arr.push(str[i]);
		}

		return arr;
	}

	/** 将字符串中敏感字用*替换返回 */
	filter(inputStr) {
		const chars = this.getCharArray(inputStr);
		let index = 0;
		let node = this.rootNode;
		let word: number[] = [];
		const len = chars.length;

		while (len >= index) {
			// 遇空格节点树停止本次遍历[敏 感  词 -> ******]
			if (chars[index] != ' ') { // 空格是结束遍历标志符
				node = this.findNode(node, chars[index]);
			}

			if (node == null) { // 遍历树结束
				index = index - word.length;
				node = this.rootNode;
				word = [];
			} else if (node.flag == 1) { // 完整敏感词
				word.push(index);
				word.forEach(v => {
					chars[v] = '*'; // 替换字符
				});

				node = this.rootNode;
				word = [];
			} else { // 未完整敏感词
				word.push(index);
			}

			index = index + 1;
		}

		let str = '';

		chars.forEach(v => {
			str += v;
		});

		return str;
	}

	/** 字符串是否合法 */
	legally(inputStr): boolean {
		return inputStr == this.filter(inputStr);
	}

}